home *** CD-ROM | disk | FTP | other *** search
/ QRZ! Ham Radio 8 / QRZ Ham Radio Callsign Database - Volume 8.iso / mac / files / t_sys5 / unixcpio.gz / unixnet.cpio / tcpuser.c < prev    next >
C/C++ Source or Header  |  1994-07-11  |  7KB  |  349 lines

  1. /* User calls to TCP */
  2. #include "global.h"
  3. #include "timer.h"
  4. #include "mbuf.h"
  5. #include "netuser.h"
  6. #include "internet.h"
  7. #include "tcp.h"
  8. #ifdef    BSD
  9. char *sprintf();
  10. #endif
  11.  
  12. int16 tcp_window = DEF_WND;
  13.  
  14. struct tcb *
  15. open_tcp(lsocket,fsocket,mode,window,r_upcall,t_upcall,s_upcall,tos,user)
  16. struct socket *lsocket;    /* Local socket */
  17. struct socket *fsocket;    /* Remote socket */
  18. int mode;        /* Active/passive/server */
  19. int16 window;        /* Receive window (and send buffer) sizes */
  20. void (*r_upcall)();    /* Function to call when data arrives */
  21. void (*t_upcall)();    /* Function to call when ok to send more data */
  22. void (*s_upcall)();    /* Function to call when connection state changes */
  23. char tos;
  24. char *user;        /* User linkage area */
  25. {
  26.     struct connection conn;
  27.     register struct tcb *tcb;
  28.     void send_syn();
  29.  
  30.     if(lsocket == NULLSOCK){
  31.         net_error = INVALID;
  32.         return NULLTCB;
  33.     }
  34.     conn.local.address = lsocket->address;
  35.     conn.local.port = lsocket->port;
  36.     if(fsocket != NULLSOCK){
  37.         conn.remote.address = fsocket->address;
  38.         conn.remote.port = fsocket->port;
  39.     } else {
  40.         conn.remote.address = 0;
  41.         conn.remote.port = 0;
  42.     }
  43.     if((tcb = lookup_tcb(&conn)) == NULLTCB){
  44.         if((tcb = create_tcb(&conn)) == NULLTCB){
  45.             net_error = NO_SPACE;
  46.             return NULLTCB;
  47.         }
  48.     } else if(tcb->state != LISTEN){
  49.         net_error = CON_EXISTS;
  50.         return NULLTCB;
  51.     }
  52.     tcb->user = user;
  53.     if(window != 0)
  54.         tcb->window = tcb->rcv.wnd = window;
  55.     else
  56.         tcb->window = tcb->rcv.wnd = tcp_window;
  57.     tcb->r_upcall = r_upcall;
  58.     tcb->t_upcall = t_upcall;
  59.     tcb->s_upcall = s_upcall;
  60.     tcb->tos = tos;
  61.     switch(mode){
  62.     case TCP_SERVER:
  63.         tcb->flags |= CLONE;
  64.     case TCP_PASSIVE:    /* Note fall-thru */
  65.         setstate(tcb,LISTEN);
  66.         break;
  67.     case TCP_ACTIVE:
  68.         /* Send SYN, go into SYN_SENT state */
  69.         tcb->flags |= ACTIVE;
  70.         send_syn(tcb);
  71.         setstate(tcb,SYN_SENT);
  72.         tcp_output(tcb);
  73.         tcp_stat.conout++;
  74.         break;
  75.     }
  76.     return tcb;
  77. }
  78. /* User send routine */
  79. int
  80. send_tcp(tcb,bp)
  81. register struct tcb *tcb;
  82. struct mbuf *bp;
  83. {
  84.     int16 cnt;
  85.     void send_syn();
  86.  
  87.     if(tcb == NULLTCB || bp == NULLBUF){
  88.         free_p(bp);
  89.         net_error = INVALID;
  90.         return -1;
  91.     }
  92.     cnt = len_mbuf(bp);
  93. #ifdef    TIGHT
  94.     /* If this would overfill our send queue, reject it entirely */
  95.     if(tcb->sndcnt + cnt > tcb->window){
  96.         free_p(bp);
  97.         net_error = WOULDBLK;
  98.         return -1;
  99.     }
  100. #endif
  101.     switch(tcb->state){
  102.     case CLOSED:
  103.         free_p(bp);
  104.         net_error = NO_CONN;
  105.         return -1;
  106.     case LISTEN:    /* Change state from passive to active */
  107.         tcb->flags |= ACTIVE;
  108.         send_syn(tcb);
  109.         setstate(tcb,SYN_SENT);    /* Note fall-thru */
  110.     case SYN_SENT:
  111.     case SYN_RECEIVED:
  112.     case ESTABLISHED:
  113.     case CLOSE_WAIT:
  114.         append(&tcb->sndq,bp);
  115.         tcb->sndcnt += cnt;
  116.         tcp_output(tcb);
  117.         break;
  118.     case FINWAIT1:
  119.     case FINWAIT2:
  120.     case CLOSING:
  121.     case LAST_ACK:
  122.     case TIME_WAIT:
  123.         free_p(bp);
  124.         net_error = CON_CLOS;
  125.         return -1;
  126.     }
  127.     return cnt;
  128. }
  129. /* User receive routine */
  130. int
  131. recv_tcp(tcb,bp,cnt)
  132. register struct tcb *tcb;
  133. struct mbuf **bp;
  134. int16 cnt;
  135. {
  136.     if(tcb == NULLTCB || bp == (struct mbuf **)NULL){
  137.         net_error = INVALID;
  138.         return -1;
  139.     }
  140.     /* cnt == 0 means "I want it all" */
  141.     if(cnt == 0)
  142.         cnt = tcb->rcvcnt;
  143.     /* If there's something on the queue, just return it regardless
  144.      * of the state we're in.
  145.      */
  146.     if(tcb->rcvcnt != 0){
  147.         /* See if the user can take all of it */
  148.         if(tcb->rcvcnt <= cnt){
  149.             cnt = tcb->rcvcnt;
  150.             *bp = tcb->rcvq;
  151.             tcb->rcvq = NULLBUF;
  152.         } else {
  153.             if((*bp = alloc_mbuf(cnt)) == NULLBUF){
  154.                 net_error = NO_SPACE;
  155.                 return -1;
  156.             }
  157.             pullup(&tcb->rcvq,(*bp)->data,cnt);
  158.             (*bp)->cnt = cnt;
  159.         }
  160.         tcb->rcvcnt -= cnt;
  161.         tcb->rcv.wnd += cnt;
  162.         /* Do a window update if it was closed */
  163.         if(cnt == tcb->rcv.wnd){
  164.             tcb->flags |= FORCE;
  165.             tcp_output(tcb);
  166.         }
  167.         return cnt;
  168.     } else {
  169.         /* If there's nothing on the queue, our action depends on what state
  170.          * we're in (i.e., whether or not we're expecting any more data).
  171.          * If no more data is expected, then simply return 0; this is
  172.          * interpreted as "end of file".
  173.          */
  174.         switch(tcb->state){
  175.         case LISTEN:
  176.         case SYN_SENT:
  177.         case SYN_RECEIVED:
  178.         case ESTABLISHED:
  179.         case FINWAIT1:
  180.         case FINWAIT2:
  181.             *bp = NULLBUF;
  182.             net_error = WOULDBLK;
  183.             return -1;
  184.         case CLOSED:
  185.         case CLOSE_WAIT:
  186.         case CLOSING:
  187.         case LAST_ACK:
  188.         case TIME_WAIT:
  189.             *bp = NULLBUF;
  190.             return 0;
  191.         }
  192.     }
  193.     return 0;    /* Not reached, but lint doesn't know that */
  194. }
  195. /* This really means "I have no more data to send". It only closes the
  196.  * connection in one direction, and we can continue to receive data
  197.  * indefinitely.
  198.  */
  199. int
  200. close_tcp(tcb)
  201. register struct tcb *tcb;
  202. {
  203.     if(tcb == NULLTCB){
  204.         net_error = INVALID;
  205.         return -1;
  206.     }
  207.     switch(tcb->state){
  208.     case LISTEN:
  209.     case SYN_SENT:
  210.         close_self(tcb,NORMAL);
  211.         return 0;
  212.     case SYN_RECEIVED:
  213.     case ESTABLISHED:
  214.         tcb->sndcnt++;
  215.         tcb->snd.nxt++;
  216.         setstate(tcb,FINWAIT1);
  217.         tcp_output(tcb);
  218.         return 0;
  219.     case CLOSE_WAIT:
  220.         tcb->sndcnt++;
  221.         tcb->snd.nxt++;
  222.         setstate(tcb,LAST_ACK);
  223.         tcp_output(tcb);
  224.         return 0;
  225.     case FINWAIT1:
  226.     case FINWAIT2:
  227.     case CLOSING:
  228.     case LAST_ACK:
  229.     case TIME_WAIT:
  230.         net_error = CON_CLOS;
  231.         return -1;
  232.     }
  233.     return -1;    /* "Can't happen" */
  234. }
  235. /* Delete TCB, free resources. The user is not notified, even if the TCB is
  236.  * not in the CLOSED state. This function should normally be called by the
  237.  * user only in response to a state change upcall to CLOSED state.
  238.  */
  239. int
  240. del_tcp(tcb)
  241. register struct tcb *tcb;
  242. {
  243.     void unlink_tcb();
  244.     struct reseq *rp,*rp1;
  245.  
  246.     if(tcb == NULLTCB){
  247.         net_error = INVALID;
  248.         return -1;
  249.     }
  250.     unlink_tcb(tcb);
  251.     stop_timer(&tcb->timer);
  252.     stop_timer(&tcb->rtt_timer);
  253.     for(rp = tcb->reseq;rp != NULLRESEQ;rp = rp1){
  254.         rp1 = rp->next;
  255.         free_p(rp->bp);
  256.         free((char *)rp);
  257.     }
  258.     tcb->reseq = NULLRESEQ;
  259.     free_p(tcb->rcvq);
  260.     free_p(tcb->sndq);
  261.     free((char *)tcb);
  262.     return 0;
  263. }
  264. /* Do printf on a tcp connection */
  265. /*VARARGS*/
  266. tprintf(tcb,message,arg1,arg2,arg3)
  267. struct tcb *tcb;
  268. char *message,*arg1,*arg2,*arg3;
  269. {
  270.     struct mbuf *bp;
  271.     int len;
  272.  
  273.     if(tcb == NULLTCB)
  274.         return 0;
  275.  
  276.     bp = alloc_mbuf(256);
  277. #ifdef    BSD
  278.     sprintf(bp->data,message,arg1,arg2,arg3);
  279.     len = bp->cnt = strlen(bp->data);
  280. #else
  281.     len = sprintf(bp->data,message,arg1,arg2,arg3);
  282.     bp->cnt = strlen(bp->data);
  283. #endif
  284.     send_tcp(tcb,bp);
  285.     return len;
  286. }
  287. /* Return 1 if arg is a valid TCB, 0 otherwise */
  288. int
  289. tcpval(tcb)
  290. struct tcb *tcb;
  291. {
  292.     register int i;
  293.     register struct tcb *tcb1;
  294.  
  295.     if(tcb == NULLTCB)
  296.         return 0;    /* Null pointer can't be valid */
  297.     for(i=0;i<NTCB;i++){
  298.         for(tcb1=tcbs[i];tcb1 != NULLTCB;tcb1 = tcb1->next){
  299.             if(tcb1 == tcb)
  300.                 return 1;
  301.         }
  302.     }
  303.     return 0;
  304. }
  305. kick_tcp(tcb)
  306. register struct tcb *tcb;
  307. {
  308.     void tcp_timeout();
  309.  
  310.     if(!tcpval(tcb))
  311.         return -1;
  312.     tcp_timeout((char *)tcb);
  313.     return 0;
  314. }
  315. reset_tcp(tcb)
  316. register struct tcb *tcb;
  317. {
  318.     close_self(tcb,RESET);
  319. }
  320. /* Return character string corresponding to a TCP well-known port, or
  321.  * the decimal number if unknown.
  322.  */
  323. char *
  324. tcp_port(n)
  325. int16 n;
  326. {
  327.     static char buf[32];
  328.  
  329.     switch(n){
  330.     case ECHO_PORT:
  331.         return "echo";
  332.     case DISCARD_PORT:
  333.         return "discard";
  334.     case FTPD_PORT:
  335.         return "ftp_data";
  336.     case FTP_PORT:
  337.         return "ftp";    
  338.     case TELNET_PORT:
  339.         return "telnet";
  340.     case SMTP_PORT:
  341.         return "smtp";
  342.         case FINGER_PORT:
  343.         return "finger";
  344.     default:
  345.         sprintf(buf,"%u",n);
  346.         return buf;
  347.     }
  348. }
  349.